#include <iostream>
#include <map>
#include <string>
using namespace std;

constexpr int cia = 1;      // 全局常量：.rodata（readonly data）
int gui1;                   // 全局变量、无初值
int gii1 = 1;               // 全局变量、有初值
map<void*, string> m;

constexpr int cib = 2;      // 再次全局常量和变量，验证变量按存储类型集中放置
int gui2, gii2 = 2;         //    定义顺序有影响，但不绝对。

void func(int ai){          // 函数参数相当于局部变量
  static int sui;           // 静态变量、未初始化：.bss段
  static int si0 = 0;       // 静态变量、初值为0：放到.bss段即可，无需占用程序。
  static int si1 = 1;       // 静态变量、初值非0：.data段
  const static int csi = 1; // 静态常量、必须初始化：.data段
  const int cei = ai + 1;   // 局部常量：.stack 并且递归调用时每层都要分配
  if(cei < 3){
    func(cei);
  }
  m[(void*)&cei] = string(".stack func_local_const_int_") + to_string(cei);
  m[&ai] = string(".stack func_arg_int_" ) + to_string(cei);
  m[&sui] = string(".bss static_uninit_int");
  m[&si0] = string(".bss static_inited_int0");
  m[&si1] = string(".data static_inited_int1");
  m[(void*)&csi] = string(".rodata const_static_int");
  // 多次调用时函数地址也不会变。这里期望输出func_3，实际结果是func_1，原因未知，值得深究。
  m[(void*)&func] = ".text func_" + to_string(cei);
}

int main(){
  int li;
  m[(void*)&main] = ".text main()"; // 函数是代码，地址位于.text代码段
  m[(void*)&cia] = ".rodata const_int_a";
  m[(void*)&cib] = ".rodata const_int_b";
  m[&gui1] = ".bss global_uninit_int1";
  m[&gui2] = ".bss global_uninit_int2";
  m[&gii1] = ".data global_inited_int1";
  m[&gii2] = ".data global_inited_int2";
  m[&li] = ".stack main_int_0";
  int *pia = new int, *pib = new int;
  m[pia] = ".heap int_a_1"; // 能确定的是堆内存从低向高分配，栈内存从高向低分配。
  m[pib] = ".heap int_b";   // 但堆和栈的相对位置与系统有关，栈不一定最高。
  delete pia; // 内存释放后再次分配“可能”被重用，地址相同的话会被覆盖。
  m[new int] = ".heap int_a_2";
  func(0);
  for(auto it = m.rbegin(), ie = m.rend(); it != ie; ++it){
    cout << it->first << ": " << it->second << endl;
  }
  cout
    << ".stack  栈内存（局部变量、函数参数）\n"
    << ".heap   堆内存（new, malloc）\n"
    << ".bss    未初始化数据段\n"
    << ".data   全局数据段\n"
    << ".rodata 只读数据段\n"
    << ".text   代码段\n";
  return 0;
}